"""DIRECT Animation Control Panel"""

__all__ = ['AnimPanel', 'ActorControl']

### SEE END OF FILE FOR EXAMPLE USEAGE ###

# Import Tkinter, Pmw, and the floater code from this directory tree.
from panda3d.core import Filename, getModelPath, ClockObject
from direct.tkwidgets.AppShell import AppShell
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from tkinter.simpledialog import askfloat
from tkinter.filedialog import askopenfilename
import Pmw
import os
import tkinter as tk


FRAMES = 0
SECONDS = 1


class AnimPanel(AppShell):
    # Override class variables
    appname = 'Anim Panel'
    frameWidth  = 675
    frameHeight = 250
    usecommandarea = 0
    usestatusarea  = 0
    index = 0

    def __init__(self, aList =  [], parent = None, session = None, **kw):
        INITOPT = Pmw.INITOPT
        if isinstance(aList, (list, tuple)):
            kw['actorList'] = aList
        else:
            kw['actorList'] = [aList]
        optiondefs = (
            ('title',               self.appname,       None),
            ('actorList',           [],                 None),
            ('Actor_label_width',   12,                 None),
        )
        self.defineoptions(kw, optiondefs)

        # direct session that spawned me, if any, used
        # for certain interactions with the session such
        # as being able to see selected objects/actors
        self.session = session

        self.frameHeight = 60 + (50 * len(self['actorList']))
        self.playList =  []
        self.id = 'AnimPanel_%d' % AnimPanel.index
        AnimPanel.index += 1
        # current index used for creating new actor controls
        self.actorControlIndex = 0
        # Initialize the superclass
        AppShell.__init__(self)

        # Execute option callbacks
        self.initialiseoptions(AnimPanel)
        # We need to know when AnimPanel is closed
        self.destroyCallBack = None

    def createInterface(self):
        # Handle to the toplevels interior
        interior = self.interior()
        menuBar = self.menuBar

        menuBar.addmenu('AnimPanel', 'Anim Panel Operations')
        # Actor control status
        menuBar.addcascademenu('AnimPanel', 'Control Status',
                               'Enable/disable actor control panels')
        menuBar.addmenuitem('Control Status', 'command',
                            'Enable all actor controls',
                            label = 'Enable all',
                            command = self.enableActorControls)
        menuBar.addmenuitem('Control Status', 'command',
                            'Disable all actor controls',
                            label = 'Disable all',
                            command = self.disableActorControls)
        # Frame Slider units
        menuBar.addcascademenu('AnimPanel', 'Display Units',
                               'Select display units')
        menuBar.addmenuitem('Display Units', 'command',
                            'Display frame counts', label = 'Frame count',
                            command = self.displayFrameCounts)
        menuBar.addmenuitem('Display Units', 'command',
                            'Display seconds', label = 'Seconds',
                            command = self.displaySeconds)
        # Reset all actor controls
        menuBar.addmenuitem('AnimPanel', 'command',
                            'Set actor controls to t = 0.0',
                            label = 'Jump all to zero',
                            command = self.resetAllToZero)
        menuBar.addmenuitem('AnimPanel', 'command',
                            'Set Actor controls to end time',
                            label = 'Jump all to end time',
                            command = self.resetAllToEnd)

        # Add some buttons to update all Actor Controls
        self.fToggleAll = 1
        b = self.createcomponent(
            'toggleEnableButton', (), None,
            tk.Button, (self.menuFrame,),
            text = 'Toggle Enable',
            command = self.toggleAllControls)
        b.pack(side = tk.RIGHT, expand = 0)

        b = self.createcomponent(
            'showSecondsButton', (), None,
            tk.Button, (self.menuFrame,),
            text = 'Show Seconds',
            command = self.displaySeconds)
        b.pack(side = tk.RIGHT, expand = 0)

        b = self.createcomponent(
            'showFramesButton', (), None,
            tk.Button, (self.menuFrame,),
            text = 'Show Frames',
            command = self.displayFrameCounts)
        b.pack(side = tk.RIGHT, expand = 0)

        self.actorFrame = None
        self.createActorControls()

        # Create a frame to hold the playback controls
        controlFrame = tk.Frame(interior)
        self.toStartButton = self.createcomponent(
            'toStart', (), None,
            tk.Button, (controlFrame,),
            text = '<<',
            width = 4,
            command = self.resetAllToZero)
        self.toStartButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.toPreviousFrameButton = self.createcomponent(
            'toPreviousFrame', (), None,
            tk.Button, (controlFrame,),
            text = '<',
            width = 4,
            command = self.previousFrame)
        self.toPreviousFrameButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.playButton = self.createcomponent(
            'playButton', (), None,
            tk.Button, (controlFrame,),
            text = 'Play', width = 8,
            command = self.playActorControls)
        self.playButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.stopButton = self.createcomponent(
            'stopButton', (), None,
            tk.Button, (controlFrame,),
            text = 'Stop', width = 8,
            command = self.stopActorControls)
        self.stopButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.toNextFrameButton = self.createcomponent(
            'toNextFrame', (), None,
            tk.Button, (controlFrame,),
            text = '>',
            width = 4,
            command = self.nextFrame)
        self.toNextFrameButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.toEndButton = self.createcomponent(
            'toEnd', (), None,
            tk.Button, (controlFrame,),
            text = '>>',
            width = 4,
            command = self.resetAllToEnd)
        self.toEndButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        self.loopVar = tk.IntVar()
        self.loopVar.set(0)
        self.loopButton = self.createcomponent(
            'loopButton', (), None,
            tk.Checkbutton, (controlFrame,),
            text = 'Loop', width = 8,
            variable = self.loopVar)
        self.loopButton.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        # add actors and animations, only allowed if a direct
        # session has been specified since these currently require
        # interaction with selected objects
        if self.session:
            menuBar.addmenuitem('File', 'command',
                                'Set currently selected group of objects as actors to animate.',
                                label = 'Set Actors',
                                command = self.setActors)
            menuBar.addmenuitem('File', 'command',
                                'Load animation file',
                                label = 'Load Anim',
                                command = self.loadAnim)

        controlFrame.pack(fill = tk.X)

    def createActorControls(self):
        # Create a frame to hold all the actor controls
        self.actorFrame = tk.Frame(self.interior())
        # Create a control for each actor
        self.actorControlList = []
        for actor in self['actorList']:
            anims = actor.getAnimNames()
            print("actor animnames: %s"%anims)
            topAnims = []
            if 'neutral' in anims:
                i = anims.index('neutral')
                del anims[i]
                topAnims.append('neutral')
            if 'walk' in anims:
                i = anims.index('walk')
                del anims[i]
                topAnims.append('walk')
            if 'run' in anims:
                i = anims.index('run')
                del anims[i]
                topAnims.append('run')
            anims.sort()
            anims = topAnims + anims
            if len(anims) == 0:
                # no animations set for this actor, don't
                # display the control panel
                continue
#            currComponents = self.components()
#            if 'actorControl%d' % index in currComponents:
#                self.destroycomponent('actorControl%d' % index)
#            ac = self.component('actorControl%d' % index)
#            if ac is None:
            ac = self.createcomponent(
                'actorControl%d' % self.actorControlIndex, (), 'Actor',
                ActorControl, (self.actorFrame,),
                animPanel = self,
                text = actor.getName(),
                animList = anims,
                actor = actor)
            ac.pack(expand = 1, fill = tk.X)
            self.actorControlList.append(ac)
            self.actorControlIndex = self.actorControlIndex + 1

        # Now pack the actor frame
        self.actorFrame.pack(expand = 1, fill = tk.BOTH)

    def clearActorControls(self):
        if self.actorFrame:
            self.actorFrame.forget()
            self.actorFrame.destroy()
            self.actorFrame = None

    def setActors(self):
        self.stopActorControls()
        actors = self.session.getSelectedActors()
        # make sure selected objects are actors, if not don't
        # use?
        aList = []
        for currActor in actors:
            aList.append(currActor)
        self['actorList'] = aList

        self.clearActorControls()
        self.createActorControls()

    def loadAnim(self):
        # bring up file open box to allow selection of an
        # animation file
        animFilename = askopenfilename(
            defaultextension = '.mb',
            filetypes = (('Maya Models', '*.mb'),
                         ('All files', '*')),
            initialdir = '/i/beta',
            title = 'Load Animation',
            parent = self.component('hull')
        )
        if not animFilename or animFilename == 'None':
            # no file selected, canceled
            return

        # add directory where animation was loaded from to the
        # current model path so any further searches for the file
        # can find it
        fileDirName = os.path.dirname(animFilename)
        fileBaseName = os.path.basename(animFilename)
        fileBaseNameBase = os.path.splitext(fileBaseName)[0]
        fileDirNameFN = Filename(fileDirName)
        fileDirNameFN.makeCanonical()
        getModelPath().prependDirectory(fileDirNameFN)
        for currActor in self['actorList']:
            # replace all currently loaded anims with specified one
#            currActor.unloadAnims(None, None, None)
            currActor.loadAnims({fileBaseNameBase:fileBaseNameBase})
        self.clearActorControls()
        self.createActorControls()

    def playActorControls(self):
        self.stopActorControls()
        self.lastT = ClockObject.getGlobalClock().getFrameTime()
        self.playList = self.actorControlList[:]
        taskMgr.add(self.play, self.id + '_UpdateTask')

    def play(self, task):
        if not self.playList:
            return Task.done
        fLoop = self.loopVar.get()
        currT = ClockObject.getGlobalClock().getFrameTime()
        deltaT = currT - self.lastT
        self.lastT = currT
        for actorControl in self.playList:
            # scale time by play rate value
            actorControl.play(deltaT * actorControl.playRate, fLoop)
        return Task.cont

    def stopActorControls(self):
        taskMgr.remove(self.id + '_UpdateTask')

    def getActorControlAt(self, index):
        return self.actorControlList[index]

    def enableActorControlAt(self, index):
        self.getActorControlAt(index).enableControl()

    def toggleAllControls(self):
        if self.fToggleAll:
            self.disableActorControls()
        else:
            self.enableActorControls()
        self.fToggleAll = 1 - self.fToggleAll

    def enableActorControls(self):
        for actorControl in self.actorControlList:
            actorControl.enableControl()

    def disableActorControls(self):
        for actorControl in self.actorControlList:
            actorControl.disableControl()

    def disableActorControlAt(self, index):
        self.getActorControlAt(index).disableControl()

    def displayFrameCounts(self):
        for actorControl in self.actorControlList:
            actorControl.displayFrameCounts()

    def displaySeconds(self):
        for actorControl in self.actorControlList:
            actorControl.displaySeconds()

    def resetAllToZero(self):
        for actorControl in self.actorControlList:
            actorControl.resetToZero()

    def resetAllToEnd(self):
        for actorControl in self.actorControlList:
            actorControl.resetToEnd()

    def nextFrame(self):
        for actorControl in self.actorControlList:
            actorControl.nextFrame()

    def previousFrame(self):
        for actorControl in self.actorControlList:
            actorControl.previousFrame()

    def setDestroyCallBack(self, callBack):
        self.destroyCallBack = callBack

    def destroy(self):
        # First clean up
        taskMgr.remove(self.id + '_UpdateTask')
        if self.destroyCallBack is not None:
            self.destroyCallBack()
            self.destroyCallBack = None
        AppShell.destroy(self)


class ActorControl(Pmw.MegaWidget):
    def __init__(self, parent = None, **kw):

        INITOPT = Pmw.INITOPT
        DEFAULT_FONT = (('MS', 'Sans', 'Serif'), 12, 'bold')
        DEFAULT_ANIMS = ('neutral', 'run', 'walk')
        animList = kw.get('animList', DEFAULT_ANIMS)
        if len(animList) > 0:
            initActive = animList[0]
        else:
            initActive = DEFAULT_ANIMS[0]
        optiondefs = (
            ('text',            'Actor',            self._updateLabelText),
            ('animPanel',       None,               None),
            ('actor',           None,               None),
            ('animList',        DEFAULT_ANIMS,      None),
            ('active',          initActive,         None),
            ('sLabel_width',    5,                  None),
            ('sLabel_font',     DEFAULT_FONT,       None),
        )
        self.defineoptions(kw, optiondefs)

        # Initialize the superclass
        Pmw.MegaWidget.__init__(self, parent)

        # Handle to the toplevels hull
        interior = self.interior()
        interior.configure(relief = tk.RAISED, bd = 2)

        # Instance variables
        self.fps = 24
        self.offset = 0.0
        self.maxSeconds = 1.0
        self.currT = 0.0
        self.fScaleCommand = 0
        self.fOneShot = 0

        # Create component widgets
        self._label = self.createcomponent(
            'label', (), None,
            tk.Menubutton, (interior,),
            font=('MSSansSerif', 14, 'bold'),
            relief = tk.RAISED, bd = 1,
            activebackground = '#909090',
            text = self['text'])
        # Top level menu
        labelMenu = tk.Menu(self._label, tearoff = 0)

        # Menu to select display mode
        self.unitsVar = tk.IntVar()
        self.unitsVar.set(FRAMES)
        displayMenu = tk.Menu(labelMenu, tearoff = 0)
        displayMenu.add_radiobutton(label = 'Frame count',
                                    value = FRAMES,
                                    variable = self.unitsVar,
                                    command = self.updateDisplay)
        displayMenu.add_radiobutton(label = 'Seconds',
                                    value = SECONDS,
                                    variable = self.unitsVar,
                                    command = self.updateDisplay)
        # Items for top level menu
        labelMenu.add_cascade(label = 'Display Units', menu = displayMenu)
        # labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
        labelMenu.add_command(label = 'Jump To Zero',
                              command = self.resetToZero)
        labelMenu.add_command(label = 'Jump To End Time',
                              command = self.resetToEnd)

        # Now associate menu with menubutton
        self._label['menu'] = labelMenu
        self._label.pack(side = tk.LEFT, fill = tk.X)

        # Combo box to select current animation
        self.animMenu = self.createcomponent(
            'animMenu', (), None,
            Pmw.ComboBox, (interior,),
            labelpos = tk.W, label_text = 'Anim:',
            entry_width = 12, selectioncommand = self.selectAnimNamed,
            scrolledlist_items = self['animList'])
        self.animMenu.selectitem(self['active'])
        self.animMenu.pack(side = 'left', padx = 5, expand = 0)

        # Combo box to select frame rate
        playRateList = ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0', '10.0']
        playRate = '%0.1f' % self['actor'].getPlayRate(self['active'])
        if playRate not in playRateList:
            playRateList.append(playRate)
            playRateList.sort(key=lambda s:eval(s))
        playRateMenu = self.createcomponent(
            'playRateMenu', (), None,
            Pmw.ComboBox, (interior,),
            labelpos = tk.W, label_text = 'Play Rate:',
            entry_width = 4, selectioncommand = self.setPlayRate,
            scrolledlist_items = playRateList)
        playRateMenu.selectitem(playRate)
        playRateMenu.pack(side = tk.LEFT, padx = 5, expand = 0)

        # Scale to control animation
        frameFrame = tk.Frame(interior, relief = tk.SUNKEN, bd = 1)
        self.minLabel = self.createcomponent(
            'minLabel', (), 'sLabel',
            tk.Label, (frameFrame,),
            text = 0)
        self.minLabel.pack(side = tk.LEFT)

        self.frameControl = self.createcomponent(
            'scale', (), None,
            tk.Scale, (frameFrame,),
            from_ = 0, to = 24, resolution = 1.0,
            command = self.goTo,
            orient = tk.HORIZONTAL, showvalue = 1)
        self.frameControl.pack(side = tk.LEFT, expand = 1)
        self.frameControl.bind('<Button-1>', self.__onPress)
        self.frameControl.bind('<ButtonRelease-1>', self.__onRelease)

        self.maxLabel = self.createcomponent(
            'maxLabel', (), 'sLabel',
            tk.Label, (frameFrame,),
            text = 24)
        self.maxLabel.pack(side = tk.LEFT)
        frameFrame.pack(side = tk.LEFT, expand = 1, fill = tk.X)

        # Checkbutton to enable/disable control
        self.frameActiveVar = tk.IntVar()
        self.frameActiveVar.set(1)
        frameActive = self.createcomponent(
            'checkbutton', (), None,
            tk.Checkbutton, (interior,),
            variable = self.frameActiveVar)
        frameActive.pack(side = tk.LEFT, expand = 1)

        # Execute option callbacks
        self.initialiseoptions(ActorControl)
        self.playRate = 1.0
        self.updateDisplay()

    def _updateLabelText(self):
        self._label['text'] = self['text']

    def updateDisplay(self):
        actor = self['actor']
        active = self['active']
        self.fps = actor.getFrameRate(active)
        if self.fps is None:
            # there was probably a problem loading the
            # active animation, set default anim properties
            print("unable to get animation fps, zeroing out animation info")
            self.fps = 24
            self.duration = 0
            self.maxFrame = 0
            self.maxSeconds = 0
        else:
            self.duration = actor.getDuration(active)
            self.maxFrame = actor.getNumFrames(active) - 1
            self.maxSeconds = self.offset + self.duration
        # switch between showing frame counts and seconds
        if self.unitsVar.get() == FRAMES:
            # these are approximate due to discrete frame size
            fromFrame = 0
            toFrame = self.maxFrame
            self.minLabel['text'] = fromFrame
            self.maxLabel['text'] = toFrame
            self.frameControl.configure(from_ = fromFrame,
                                        to = toFrame,
                                        resolution = 1.0)
        else:
            self.minLabel['text'] = '0.0'
            self.maxLabel['text'] = "%.2f" % self.duration
            self.frameControl.configure(from_ = 0.0,
                                        to = self.duration,
                                        resolution = 0.01)

    def __onPress(self, event):
        # Enable slider command
        self.fScaleCommand = 1

    def __onRelease(self, event):
        # Disable slider command
        self.fScaleCommand = 0

    def selectAnimNamed(self, name):
        # Update active anim
        self['active'] = name
        # Reset play rate
        self.component('playRateMenu').selectitem('1.0')
        self.setPlayRate('1.0')
        # Move slider to zero
        self.resetToZero()

    def setPlayRate(self, rate):
        # set play rate on the actor, although for the AnimPanel
        # purpose we don't use the actor's play rate, but rather
        # the self.playRate value since we drive the animation
        # playback ourselves
        self['actor'].setPlayRate(eval(rate), self['active'])
        self.playRate = eval(rate)
        self.updateDisplay()

    def setOffset(self):
        newOffset = askfloat(parent = self.interior(),
                             title = self['text'],
                             prompt = 'Start offset (seconds):')
        if newOffset is not None:
            self.offset = newOffset
            self.updateDisplay()

    def enableControl(self):
        self.frameActiveVar.set(1)

    def disableControl(self):
        self.frameActiveVar.set(0)

    def displayFrameCounts(self):
        self.unitsVar.set(FRAMES)
        self.updateDisplay()

    def displaySeconds(self):
        self.unitsVar.set(SECONDS)
        self.updateDisplay()

    def play(self, deltaT, fLoop):
        if self.frameActiveVar.get():
            # Compute new time
            self.currT = self.currT + deltaT
            if fLoop and self.duration:
                # If its looping compute modulo
                loopT = self.currT % self.duration
                self.goToT(loopT)
            else:
                if self.currT > self.maxSeconds:
                    # Clear this actor control from play list
                    self['animPanel'].playList.remove(self)
                else:
                    self.goToT(self.currT)
        else:
            # Clear this actor control from play list
            self['animPanel'].playList.remove(self)

    def goToF(self, f):
        if self.unitsVar.get() == FRAMES:
            self.frameControl.set(f)
        else:
            self.frameControl.set(f / self.fps)

    def goToT(self, t):
        if self.unitsVar.get() == FRAMES:
            self.frameControl.set(t * self.fps)
        else:
            self.frameControl.set(t)

    def goTo(self, t):
        # Convert scale value to float
        t = float(t)
        # Now convert t to seconds for offset calculations
        if self.unitsVar.get() == FRAMES:
            t = t / self.fps
        # Update currT
        if self.fScaleCommand or self.fOneShot:
            self.currT = t
            self.fOneShot = 0
        # Now update actor (pose specifed as frame count)
        self['actor'].pose(self['active'],
                           min(self.maxFrame, int(t * self.fps)))

    def resetToZero(self):
        # This flag forces self.currT to be updated to new value
        self.fOneShot = 1
        self.goToT(0)

    def resetToEnd(self):
        # This flag forces self.currT to be updated to new value
        self.fOneShot = 1
        self.goToT(self.duration)

    def nextFrame(self):
        """
        There needed to be a better way to select an exact frame number
        as the control slider doesn't have the desired resolution
        """
        self.fOneShot = 1
        self.goToT((self.currT+(1/self.fps))%self.duration)

    def previousFrame(self):
        """
        There needed to be a better way to select an exact frame number
        as the control slider doesn't have the desired resolution
        """
        self.fOneShot = 1
        self.goToT((self.currT-(1/self.fps))%self.duration)


"""
# EXAMPLE CODE
from direct.actor import Actor
import AnimPanel

a = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
                 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
                 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
                {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
                         "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
                 "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
                          "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
                 "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
                         "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
a.attach("head", "torso", "joint-head", 250)
a.attach("torso", "legs", "joint-hips", 250)
a.attach("head", "torso", "joint-head", 500)
a.attach("torso", "legs", "joint-hips", 500)
a.attach("head", "torso", "joint-head", 1000)
a.attach("torso", "legs", "joint-hips", 1000)
a.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
a.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
a.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
a.setLOD(250, 250, 75)
a.setLOD(500, 75, 15)
a.setLOD(1000, 15, 1)
a.fixBounds()
a.reparentTo(render)


a2 = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
                 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
                 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
                      "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
                      "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
                {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
                         "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
                 "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
                          "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
                 "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
                         "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
a2.attach("head", "torso", "joint-head", 250)
a2.attach("torso", "legs", "joint-hips", 250)
a2.attach("head", "torso", "joint-head", 500)
a2.attach("torso", "legs", "joint-hips", 500)
a2.attach("head", "torso", "joint-head", 1000)
a2.attach("torso", "legs", "joint-hips", 1000)
a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
a2.setLOD(250, 250, 75)
a2.setLOD(500, 75, 15)
a2.setLOD(1000, 15, 1)
a2.fixBounds()
a2.reparentTo(render)

ap = AnimPanel.AnimPanel([a, a2])

# Alternately
ap = a.animPanel()
ap2 = a2.animPanel()

"""
